<?php
namespace Common\Model;
use Think\Model;
abstract class BaseModel extends Model{

	protected function _initialize() {
		parent::_initialize();
		//由于很多查询操作没有回调方法无法自动更新缓存，所以打开缓存这个操作只放到有回调方法的select和find中去
		//$this -> cache(TRUE);
	}

	/**
	 * 批量Update 两种模式
	 * 模式一:传入二维数组如 array(array('id' => 1, 'name' => 'nickname', 'age' => 20));
	 * 模式二:传入一维数组如 array(1 => 'nickname'); 此时必需传入when和set 才能知道要更新什么字段依据什么字段
	 * @param  array  $data		要更新的数据
	 * @param  string $when		依据什么字段
	 * @param  string $set		传入一维数组时说明要更新哪个字段
	 * @return false | integer	更新成功时返回影响的行数 失败时返回false
	 */
	public function saveBatch($data, $when, $set = FALSE){
		if(!is_array(current($data)) && !$set){
			return;
		}

		$sets = $set ? array($set) : array();
		$element = current($data);
		foreach ($element as $element_k => $element_v) {
			$element_k != $when && $sets[] = $element_k;
		}

		$loops = array();
		foreach ($data as $data_k => $data_v) {
			foreach ($sets as $set_item) {
				if ($set) {
					$loops[$set][$data_k] = $data_v;
				} else {
					$loops[$set_item][$data_v[$when]] = $data_v[$set_item];
				}
			}
		}

		$sql_array = array();
		$sql_where_ids = array();	//批量更新必需指定要更新哪些ID
		$sql_item = 'UPDATE ' . $this -> getTableName() . ' SET ';
		foreach ($loops as $loop_k => $loop_v) {
			$sql_item .= '`'.$loop_k.'` = CASE `'.$when.'` ';
			foreach ($loop_v as $loop_v_k => $loop_v_v) {
				$sql_item .= ' WHEN \''.$loop_v_k.'\' THEN \''.$loop_v_v.'\'';
				$sql_where_ids[] = $loop_v_k;
			}
			$sql_item .= ' END ';
			$sql_array[] = $sql_item;
		}
		$sql = implode(',', $sql_array);
		$sql .= 'WHERE `'.$when.'` IN ('.implode(',', $sql_where_ids).')';

		$result = $this -> execute($sql);

		if(false !== $result && is_numeric($result)) {
			$this->_after_update(array(),array());
		}

		return $result;
	}

	public function select($options = array()){
		!isset($options ['cache']) && $this -> cache(TRUE);		//如未打开缓存则打开缓存
		$options_bak = $this -> options;
		$options_parsed = $this -> _parseOptions($this -> options);
		$this -> options = $options_bak;
		$resultSet = parent::select($options);
		if (empty($resultSet)) {
			$this -> _after_select($resultSet, $options_parsed);
		}
		return $resultSet;
	}

	public function find($options=array()){
		!isset($options ['cache']) && $this -> cache(TRUE);		//如未打开缓存则打开缓存
		return parent::find($options);
	}

	//selectAdd, 这些操作后没有回调方法，无法标记数据为已更改
	public function addAll($dataList, $options = array(), $replace = false){
		$result = parent::addAll($dataList, $options, $replace);
		if(false !== $result && is_numeric($result)) {
			$this->_after_insert(array(),array());
		}
		return $result;
	}

	public function selectAdd($fields='',$table='',$options=array()) {
		$result = parent::addAll($fields, $table, $options);
		if(false !== $result && is_numeric($result)) {
			$this->_after_insert(array(),array());
		}
		return $result;
	}

	protected function _after_insert($data, $options){
		$this -> _clear_cache();
	}

	protected function _after_update($data, $options){
		$this -> _clear_cache();
	}

	protected function _after_delete($data, $options){
		$this -> _clear_cache();
	}

	//除了select,find之外的其它查询没有回调方法，无法标记key以更新缓存
	protected function _after_select(&$resultSet,$options) {
		if (isset($options ['cache'])) {
			$cache = $options['cache'];
			$key = is_string($cache['key']) ? $cache ['key'] : md5(serialize($options));
			$cache_keys = S($this -> getTableName().'-keys');
			if (!$cache_keys || !in_array($key, $cache_keys)){
				$cache_keys[] = $key;
				S($this -> getTableName().'-keys', $cache_keys);
			}
		}
	}

	protected function _after_find(&$result,$options) {
		if (!$options['result'] && isset($options ['cache'])) {
			$cache = $options['cache'];
			$key = is_string($cache['key']) ? $cache ['key'] : md5(serialize($options));
			$cache_keys = S($this -> getTableName().'-keys');
			if (!$cache_keys || !in_array($key, $cache_keys)){
				$cache_keys[] = $key;
				S($this -> getTableName().'-keys', $cache_keys);
			}
		}
	}

	protected function _clear_cache(){
		//删除与该表相关的所有key的缓存
		$cache_keys = S($this -> getTableName().'-keys');
		foreach ($cache_keys as $key) {
			S($key, NULL);
		}
		S($this -> getTableName().'-keys', NULL);

		//删除完缓存重新设为缓存可用
		S($this -> getTableName().'-cached', TRUE);
	}


	  /**
     * 删除表
     */
    final public function drop_table($tablename) {
        $tablename = C("DB_PREFIX") . $tablename;
        return $this->query("DROP TABLE $tablename");
    }

    /**
     * 读取全部表名
     */
    final public function list_tables() {
        $tables = array();
        $data = $this->query("SHOW TABLES");
        foreach ($data as $k => $v) {
            $tables[] = $v['tables_in_' . strtolower(C("DB_NAME"))];
        }
        return $tables;
    }

    /**
     * 检查表是否存在
     * $table 不带表前缀
     */
    final public function table_exists($table) {
        $tables = $this->list_tables();
        return in_array(C("DB_PREFIX") . $table, $tables) ? true : false;
    }

    /**
     * 获取表字段
     * $table 不带表前缀
     */
    final public function get_fields($table) {
        $fields = array();
        $table = C("DB_PREFIX") . $table;
        $data = $this->query("SHOW COLUMNS FROM $table");
        foreach ($data as $v) {
            $fields[$v['Field']] = $v['Type'];
        }
        return $fields;
    }

    /**
     * 检查字段是否存在
     * $table 不带表前缀
     */
    final public function field_exists($table, $field) {
        $fields = $this->get_fields($table);
        return array_key_exists($field, $fields);
    }

    protected function _before_write(&$data) {

    }
}